const createError = require('http-errors');
const mongoose = require('mongoose');
const passportLocalMongoose = require('passport-local-mongoose');
// const passport = require('passport');
// const LocalStrategy = require('passport-local').Strategy;

const pwdReg = require('../../utils/pwd-reg');

const { Schema, model } = mongoose;

const AccountSchema = new Schema({
  email: {
    type: String,
    required: true,
    index: true, // 布尔值 是否对这个属性创建索引
    // unique: 布尔值 是否对这个属性创建唯一索引
    // sparse: 布尔值 是否对这个属性创建稀疏索引
  },
  nickname: {
    type: String,
    default: '',
    /**
     * String
     * lowercase: 布尔值 是否在保存前对此值调用 .toLowerCase()
     * uppercase: 布尔值 是否在保存前对此值调用 .toUpperCase()
     * trim: 布尔值 是否在保存前对此值调用 .trim()
     * match: 正则表达式 创建验证器检查这个值是否匹配给定正则表达式
     * enum: 数组 创建验证器检查这个值是否包含于给定数组
     */
  },
  phone: {
    type: String,
    default: '',

    // select: false, // 是否被 query
    // get: v => Math.round(v),
    // set: v => Math.round(v),
    validate: {
      validator: v => {
        if (v) return /^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(v);
        return true;
      },
      message: '{VALUE} is not a valid phone number!',
    },
    alias: 'i', // 别名`instant.phone===instant.i`
  },
  salt: {
    type: String,
    select: false,
  },
  hash: {
    type: String,
    select: false,
  },
  attempts: {
    type: Number,
    // min: 数值 创建验证器检查属性是否大于或等于该值
    // max: 数值 创建验证器检查属性是否小于或等于该值
  },
  last: {
    type: String,
    get: v => {
      console.log(v, typeof v);
      return new Date(v).toLocaleString();
    },
    set: v => {
      console.log(v, typeof v);
      return new Date(v).toLocaleString();
    },
  },
  created_at: {
    type: Date,
    default: Date.now,
    // min: Date
    // max: Date
  },
  update_at: {
    type: Date,
    default: Date.now,
  },
  destroy_at: {
    type: Date,
    default: null,
  },
});

AccountSchema.plugin(passportLocalMongoose, {
  limitAttempts: true, // 指定是否應限制登錄嘗試和應懲罰登錄失敗。默認值：false。
  maxAttempts: 10, // 指定在阻止登錄之前允許的最大失敗嘗試次數。默認值：無窮大。
  interval: 100, // 指定兩次登錄嘗試之間的時間間隔（以毫秒為單位），該間隔基於失敗嘗試的次數呈指數增加，最大為maxInterval。默認值：100
  maxInterval: 6000, // 指定可以鎖定帳戶的最長時間。默認值30000（5分鐘）
  usernameField: 'email', // 指定保存用戶名的字段名稱。默認為“用戶名”。如果要使用其他字段來保存用戶名，例如“電子郵件”
  // usernameQueryFields: [], // 指定用于标识用户的模型的可选字段（例如电子邮件）。
  usernameUnique: true, // 指定是否應通過mongodb索引將用戶名字段強制為唯一。默認為true。
  saltField: 'salt', // 指定包含鹽值的字段名稱。默認為`salt`。
  hashField: 'hash', // 指定用於保存密碼哈希值的字段名稱。默認為`hash`。
  letsField: 'attempts', // 指定字段名稱，該字段名稱保存自上次成功登錄以來的登錄失敗次數。默認為`attempts`。
  lastLoginField: 'last', // 指定保存上一次登錄嘗試時間戳的字段名稱。默認為`last`。
  selectFields: undefined, // 指定要從mongodb中選擇（並存儲在會話中）的模型的字段。默認為 undefined ，以便選擇模型的所有字段。
  /**
   * 验证`Account.authenticate('local')(email, password)`时调用此函数,但是在这里过滤掉destroy_at导致显示error信息不对
   */
  findByUsername: (mAccount, queryParameters) => (
    // 限制查詢的選項
    // queryParameters:  { '$or': [ { email: 't6@163.com' } ] }
    mAccount.findOne({
      ...queryParameters,
      // destroy_at: null,
    })
  ),
  passwordValidator: (password, cb) => {
    if (password && pwdReg(password)) {
      // return an empty cb() on success
      return cb();
    }
    return cb(createError({
      name: 'ValidationError',
      message: 'Validation error: Validation is on password failed',
      errors: [],
    }));
  },
});

// 名称复数化机制
module.exports = model('accounts', AccountSchema);
